{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "from collections import Counter\n",
    "from ML.metrics import accuracy_score\n",
    "from ML.model_selection import train_test_split"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "class KNeighborsClassifier():\n",
    "\n",
    "    def __init__(self, k=5, p=2):\n",
    "        assert k > 0, 'k需要大于0'\n",
    "        assert p > 0, 'p需要大于0'\n",
    "        self.k = k\n",
    "        self.p = p\n",
    "\n",
    "        self._X_train = None\n",
    "        self._y_train = None\n",
    "\n",
    "    def fit(self,X_train,y_train):\n",
    "        '''训练函数'''\n",
    "        assert X_train.shape[0] == y_train.shape[0], 'X_train中的样本数需要与y_train中相同'\n",
    "        assert self.k <= y_train.shape[0], 'k需要小于或等于样本总数'\n",
    "        self._X_train = X_train\n",
    "        self._y_train = y_train\n",
    "\n",
    "    def predict(self,X_predict):\n",
    "        '''预测函数'''\n",
    "        assert self._X_train.shape[1] == X_predict.shape[1], '预测的特征数量需要和样本的特征数量相同'\n",
    "\n",
    "        return np.array([self._predict(x) for x in X_predict])\n",
    "\n",
    "\n",
    "    def _predict(self,x):\n",
    "        \n",
    "        distances = [distance(item,x,p = self.p) for item in self._X_train]\n",
    "        nearest = np.argsort(distances)[:self.k]\n",
    "        k_labels = self._y_train[nearest]\n",
    "        return Counter(k_labels).most_common(1)[0][0]\n",
    "\n",
    "    def score(self,X_test,y_test):\n",
    "        '''检测模型得分'''\n",
    "        y_predict = self.predict(X_test)\n",
    "        return accuracy_score(y_test, y_predict)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [],
   "source": [
    "def distance(a,b,p=2):  # p=1 就是曼哈顿距离 p=2 就是欧拉距离\n",
    "    '''计算距离的算法'''\n",
    "    return np.sum(np.abs(a - b) ** p) ** (1/p)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 1.导入数据并拆分训练数据和预测数据"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [],
   "source": [
    "X = np.loadtxt('data/x.txt')\n",
    "y = np.loadtxt('data/y.txt')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [],
   "source": [
    "X_train,X_test,y_train,y_test = train_test_split(X,y,test_size=0.25,seed=100)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 2.机器学习训练数据,建立模型"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [],
   "source": [
    "knn_clf = KNeighborsClassifier(k=5, p=2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [],
   "source": [
    "knn_clf.fit(X_train,y_train)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 3.预测并计算模型对预测数据的评分"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0.972972972972973"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "knn_clf.score(X_test,y_test)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 4.用网格搜索对参数k,p进行调优"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "best_k:7,best_score:1.0,best_p:2\n"
     ]
    }
   ],
   "source": [
    "best_score = 0\n",
    "best_k = 0\n",
    "best_p = 0\n",
    "for k in range(1,20):\n",
    "    for p in range(1,20):\n",
    "        knn_clf = KNeighborsClassifier(k=k, p=p)\n",
    "        knn_clf.fit(X_train,y_train)\n",
    "        score = knn_clf.score(X_test,y_test)\n",
    "        if score > best_score:\n",
    "            best_score = score\n",
    "            best_k = k\n",
    "            best_p = p\n",
    "\n",
    "print('best_k:{},best_score:{},best_p:{}'.format(best_k,best_score,best_p))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
